home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’92 / battmonitor ƒ / batt monitor.p < prev    next >
Encoding:
Text File  |  1992-04-27  |  26.0 KB  |  1,173 lines  |  [TEXT/MPS ]

  1. Program BattMonitor;
  2. {$R+} 
  3. {$OV+}
  4. {$W+} 
  5. {$SC+}
  6. {$D+}
  7. {
  8. Created: Wednesday, June 17, 1992 at 10:39 PM 
  9.     creator = 'Batø'  BattMonitor
  10.  
  11.     vers    who        what
  12.     0.00    jcr6    file created
  13.     0.02    jcr6    fixed ScrollRect bug?
  14.     0.03    jcr6    inval rather than redraw..
  15.     0.04    jcr6    sample down /1 /2 /3 /4 for both arrays
  16.     0.05    jcr6    add DLOG 128 - about box
  17.     
  18.     
  19.     jcr6 = J. Christian Russ, Analytical Vision, Inc.
  20.            ALink:D3115
  21.     
  22.     Written June 17-18, 1992 at MacHack
  23.     By J. Christian Russ
  24.            
  25.     }
  26.  
  27. USES
  28.      Memtypes,OSIntf,Menus,Dialogs,Desk,Quickdraw,Fonts,
  29.     ToolUtils,Windows,Resources,power;
  30.  
  31. CONST    
  32.     AppleMenu = 128;
  33.     FileMenu = 129;
  34.     EditMenu = 130;
  35.     ViewMenu = 131;
  36.     
  37.     QueueSize = 1000; {1000 fast samples, 1000 slow samples}
  38.     
  39.     SecTicks = {60}6; {1/10 sec}
  40.     MinTicks = {3600}60; {every 1 sec}
  41.     svWidth = 240;
  42.     MyAboutBox = 128;
  43. TYPE
  44.     PwrState = PACKED RECORD {xx bytes}
  45.                     pvolts : integer; {need to sign extend for derivative}
  46.                     pbacklight : byte;
  47.                     pIdle : boolean;
  48.                     pDiskOn : boolean;
  49.                     pSndOn : boolean;
  50.                     pModemOn : boolean;
  51.                     pPortA : boolean;
  52.                     pPortB : boolean; {modem}
  53.                     pCharging : boolean;
  54.                END; {PwrState}
  55.                
  56.     History = Array[0..QueueSize-1] of PwrState;
  57. VAR
  58.     theerr:oserr;
  59.     myhandle : handle;
  60.  
  61.     ProgState : (ForegroundP,BackgroundP);
  62.  
  63.       AppleMenuH,
  64.     FileMenuH,
  65.     EditMenuH,
  66.     ViewMenuH : MenuHandle;
  67.     
  68.     finished : boolean;
  69.     Updating : boolean;
  70.     hascolor : boolean;
  71.     
  72.     mywindow : windowptr;
  73.     
  74.     watch : curshandle;
  75.     hasWNE : boolean;        { has waitnextevent }
  76.  
  77.     SecHistory,    {history for the last xxx seconds}
  78.     dSecHistory,
  79.     MinHistory,
  80.     dMinHistory : History;
  81.     
  82.     SecStart,SecEnd : integer; {queue indicies, SecEnd=location for next entry}
  83.     MinStart,MinEnd : integer; {queue indicies, minEnd=location for next entry}
  84.     
  85.     lastMinCount,
  86.     lastSecCount : longint; {ticks for last inclusion into history arrays}
  87.     
  88.     bmode : (seconds, minutes, dseconds,dminutes);
  89.     sampledown : integer; {1,2,3, or 4}
  90.     drawmod  :integer; {counter, whether it is time to draw a new value}
  91.     
  92. PROCEDURE MacsBug; INLINE $A9FF;
  93.  
  94. FUNCTION GetVoltage : integer ; External;
  95.  
  96. FUNCTION TrapAvailable(tNumber:Integer; tType:TrapType):Boolean;
  97. CONST UnimplementedTrapNumber = $A89F;
  98. BEGIN
  99.     TrapAvailable:= ( NGetTrapAddress(tNumber,tType) <> GetTrapAddress(UnimplementedTrapNumber) )
  100. END;{TrapAvailable}
  101.  
  102.  
  103. FUNCTION WNEIsImplemented:boolean;
  104. CONST WNETrapNumber = $A860;
  105. VAR
  106.     theWorld    : SysEnvRec;
  107.     Err        : OsErr;
  108. BEGIN
  109.     Err:=SysEnvirons(1,theWorld); {Maybe I should use gestalt???}
  110.     
  111.     if theWorld.machineType<0 then
  112.         WNEIsImplemented:=false
  113.     else
  114.         WNEIsImplemented:=TrapAvailable(WNETrapNumber,ToolTrap)
  115. END;{WNEisImplemented}
  116.  
  117. FUNCTION ShouldIDoColor : boolean;
  118. VAR myGDHandle : GDHandle;
  119.     screendepth : integer;
  120. BEGIN
  121.     {++++ check trapavailable for GetGDevice}
  122.     HasColor:=false;
  123.     if not TrapAvailable($AA32,tooltrap) then
  124.         BEGIN
  125.             ShouldIDoColor:=false;
  126.             exit(ShouldIDoColor);
  127.         END;
  128.     myGDHandle:=GetGDevice;
  129.     if myGDHandle=NIL then
  130.         ShouldIDoColor:=false
  131.     else
  132.         BEGIN
  133.             HasColor:=true;
  134.             ScreenDepth:=mygdhandle^^.gdPmap^^.pixelSize;
  135.             ShouldIDoColor:=ScreenDepth>=4;
  136.         END;
  137. END;{ShouldIDoColor}
  138.  
  139.  
  140. FUNCTION myGetNextEvent(eventMask:Integer; var theEvent:EventRecord):boolean;
  141. BEGIN
  142.     if hasWNE then
  143.         myGetNextEvent:=WaitNextEvent(eventMask,theEvent,5{ticks},nil)
  144.     else
  145.         myGetNextEvent:=GetNextEvent(eventMask,theEvent)
  146. END;
  147.  
  148.  
  149. FUNCTION OptionKeyDown : Boolean;
  150. TYPE KeyPtrType=^KeyMap;
  151. VAR KeyPtr:KeyPtrType; keys:ARRAY[0..3] OF LongInt;
  152. BEGIN KeyPtr:=KeyPtrType(@keys); GetKeys(KeyPtr^);
  153.     OptionKeyDown:=(BAND(keys[1],4))<>0;
  154. END;{OptionKeyDown}
  155.  
  156. FUNCTION ShiftKeyDown : Boolean;
  157. TYPE KeyPtrType=^KeyMap;
  158. VAR KeyPtr:KeyPtrType; keys:ARRAY[0..3] OF LongInt;
  159. BEGIN KeyPtr:=KeyPtrType(@keys); GetKeys(KeyPtr^);
  160.     ShiftKeyDown:=(BAND(keys[1],1))<>0; 
  161. END;{ShiftKeyDown}
  162.  
  163. FUNCTION CommandKeyDown : Boolean;
  164. TYPE KeyPtrType=^KeyMap;
  165. VAR KeyPtr:KeyPtrType; keys:ARRAY[0..3] OF LongInt;
  166. BEGIN KeyPtr:=KeyPtrType(@keys); GetKeys(KeyPtr^);
  167.     CommandKeyDown:=(BAND(keys[1],$8000))<>0; {For MPW}
  168. END;{CommandKeyDown}
  169.  
  170.  
  171. PROCEDURE SetMenuItem (menuh:menuhandle; itemnum:integer; on:boolean);
  172. {Enable or disable menuh's itemnum}
  173. BEGIN
  174.     if menuH=NIL then exit(setMenuItem);
  175.     IF on
  176.         THEN EnableItem(menuh,itemnum)
  177.         ELSE DisableItem(menuh,itemnum);
  178.     IF ItemNum=0 THEN DrawMenuBar;
  179. END;{SetMenuItem}
  180.     
  181.     
  182. PROCEDURE ShowWatch;
  183. BEGIN
  184.     watch := GetCursor(WatchCursor);
  185.     SetCursor(watch^^);
  186. END;{showWatch}
  187.  
  188.  
  189. PROCEDURE OutlineButton(theDialog: DialogPtr; itemNo, CornerRad: integer);
  190. { Draws a border around a button. 16 is the normal cornerRad for small buttons }
  191. VAR
  192.     itemType: Integer;
  193.     itemBox: Rect;
  194.     itemHdl: Handle;
  195.     tempPort: GrafPtr;
  196. BEGIN
  197.     GetPort(tempPort);
  198.     SetPort(theDialog);
  199.     GetDItem(theDialog, itemNo, itemType, itemHdl, itemBox);
  200.     PenSize(3, 3);
  201.     InSetRect(itemBox, -4, -4);
  202.     FrameRoundRect(itemBox, cornerRad, cornerRad);
  203.     PenSize(1,1);
  204.     SetPort(tempPort);
  205. END;
  206.  
  207. PROCEDURE DimButton(TheDialog : DialogPtr; item : integer);
  208. VAR ItemType : integer;
  209.     ItemBox : rect;
  210.     ItemHdl : handle;
  211. BEGIN
  212.     GetDItem(TheDialog,item,ItemType,ItemHdl,ItemBox);
  213.     HiliteControl(pointer(ItemHdl),255); {grey the button}
  214. END; {DimButton}
  215.  
  216. PROCEDURE unDimButton(TheDialog : DialogPtr; item : integer);
  217. VAR ItemType : integer;
  218.     ItemBox : rect;
  219.     ItemHdl : handle;
  220. BEGIN
  221.     GetDItem(TheDialog,item,ItemType,ItemHdl,ItemBox);
  222.     HiliteControl(pointer(ItemHdl),0); {enable the button}
  223. END; {unDimButton}
  224.  
  225.  
  226. PROCEDURE DoAbout; {About me!!}
  227. VAR item : integer;
  228.     mylog : dialogptr;
  229. BEGIN
  230.     mylog:=GetNewDialog(myaboutbox,NIL,pointer(-1));
  231.     outlinebutton(mylog,1,16);
  232.     REPEAT
  233.         ModalDialog(nil,item);
  234.     UNTIL item=1;
  235.     disposeDialog(mylog);
  236. END;{DoAbout}
  237.  
  238.  
  239. PROCEDURE SysResume;
  240. BEGIN
  241.     FlushEvents(EveryEvent, 0);
  242.     ExitToShell;
  243. END;
  244.  
  245.  
  246. FUNCTION Uppercase(a : str255) : str255;
  247. VAR i : integer; s:str255;
  248. BEGIN
  249.     s:=a;
  250.     if ord(s[0])>0 then
  251.         for i:=1 to ord(s[0]) do
  252.             if s[i] in ['a'..'z'] then s[i]:=chr(ord(s[i])-32);
  253.     Uppercase:=s;
  254. END; {uppercase}
  255.  
  256.  
  257. PROCEDURE ChkOnOffItem(MenuH : MenuHandle; item,fst,lst : integer);
  258. VAR i : integer;
  259. BEGIN
  260.     for i:=fst to lst do
  261.         if i=item then Checkitem(MenuH,i,true)
  262.                   else CheckItem(MenuH,i,false);
  263. END; {ChkOnOffItem}
  264.  
  265.  
  266. PROCEDURE UpdateMenus;
  267. VAR tport : grafptr;
  268.     i : integer;
  269.     showitems : boolean;
  270. BEGIN
  271.     getport(tport);  {inval just the buttons that changed}
  272.     setport(mywindow);
  273.     setport(tport);
  274.     
  275.     {FileMenuH}
  276.       SetMenuItem(FileMenuH,12,true); {Quit}
  277.     
  278.     {EditMenuH}
  279.     
  280.     {ViewMenuH}
  281.     {ChkOnOffItem(ViewMenuH,ord4(DBQueryMode)+1,1,10);}
  282.     
  283. END; {UpdateMenus}
  284.  
  285.  
  286. PROCEDURE SetUpMenus;
  287. VAR
  288.     Apple:str255;
  289.     Item,FontID:integer;
  290. BEGIN
  291.     AppleMenuH:=GetMenu(AppleMenu);
  292.     AddResMenu(AppleMenuH, 'DRVR');
  293.     InsertMenu(AppleMenuH, 0);
  294.     
  295.     FileMenuH := GetMenu(FileMenu);
  296.     InsertMenu(FileMenuH, 0);
  297.     
  298.     EditMenuH := GetMenu(EditMenu);
  299.     InsertMenu(EditMenuH, 0);
  300.     
  301.     ViewMenuH := GetMenu(ViewMenu);
  302.     InsertMenu(ViewMenuH, 0);
  303.  
  304.     DrawMenuBar;  
  305. END; {SetUpMenus}
  306.  
  307. PROCEDURE ScrollVolts(draweverything : boolean); Forward;
  308.  
  309. PROCEDURE DoMenuEvent (MenuChoice : LongInt);
  310. VAR
  311.   MenuID,MenuItem,i,ignore:integer;
  312.   name,astr,ItemName:str255;
  313.   tport : grafptr;
  314. BEGIN
  315.     MenuID := HiWord(MenuChoice);
  316.     MenuItem := LoWord(MenuChoice);
  317.  
  318.     CASE MenuID OF
  319.     AppleMenu:
  320.            BEGIN
  321.                 IF MenuItem=1 THEN 
  322.                     BEGIN
  323.                         DoAbout;
  324.                     END
  325.             ELSE BEGIN
  326.                     GetItem(GetMHandle(AppleMenu),MenuItem,name);
  327.                     ignore:=OpenDeskAcc(name)
  328.                  END;
  329.          END;
  330.  
  331.     FileMenu:
  332.         BEGIN 
  333.             CASE MenuItem OF
  334.             1..11:;{Blah!!!}
  335.            12:Finished:=true;  {QUIT!}
  336.             END;{case}
  337.         END;
  338.  
  339.    EditMenu:
  340.        BEGIN
  341.              GetItem(GetMHandle(EditMenu), MenuItem, ItemName);
  342.              IF NOT SystemEdit(MenuItem - 1) THEN
  343.             CASE MenuItem OF
  344.             1:; {UNDO}
  345.                
  346.            {2:-}
  347.             3:{DoCut};
  348.             4:{DoCopy};
  349.             5:{DoPaste};
  350.             6:{DoClear};
  351.              END;{case}
  352.        END;
  353.  
  354.     ViewMenu:
  355.            BEGIN
  356.              CASE MenuItem OF
  357.                1:{voltage}
  358.                 BEGIN
  359.                     if bmode=dseconds then bmode:=seconds;
  360.                     if bmode=dminutes then bmode:=minutes;
  361.                 END;
  362.                2:{current}
  363.                 BEGIN
  364.                     if bmode=seconds then bmode:=dseconds;
  365.                     if bmode=minutes then bmode:=dminutes;
  366.                 END;
  367.               {3:-}
  368.             4..7:{1/10,2/10,3/10,4/10 second}
  369.                 BEGIN
  370.                     if bmode=minutes then bmode:=seconds;
  371.                     if bmode=dminutes then bmode:=dseconds;
  372.                     sampledown:=MenuItem-3;
  373.                 END;
  374.             8..11:
  375.                 BEGIN
  376.                     if bmode=seconds then bmode:=minutes;
  377.                     if bmode=dseconds then bmode:=dminutes;
  378.                     sampledown:=Menuitem-7;
  379.                 END;
  380.              END;{case}
  381.             drawmod:=0; {modulo 0..sampledown-1}
  382.             {ScrollVolts(true);}
  383.             getport(tport);
  384.             setport(mywindow);
  385.             invalrect(mywindow^.portrect);
  386.             setport(tport);
  387.            END;
  388.     END; {case MenuNumber}
  389.  
  390.     HiliteMenu(0);
  391.     UpdateMenus;
  392. END;{DoMenuEvent}
  393.  
  394.  
  395. PROCEDURE DoKeyDown(event:EventRecord);
  396. VAR
  397.     Ch : char;
  398. BEGIN
  399.     Ch := chr(BitAnd(Event.message, 255));
  400.     IF BitAnd(Event.modifiers,CmdKey)=CmdKey THEN
  401.         BEGIN            
  402.             UpdateMenus;
  403.             DoMenuEvent(MenuKey(Ch));
  404.             exit(DoKeyDown);
  405.         END;
  406.         
  407.     CASE ORD(ch) of
  408.         {Esc}         27: BEGIN 
  409.                          END;
  410.         {F1}
  411.         {F2}
  412.         {Tab}         9: BEGIN
  413.                          END;
  414.         {Return}     13,
  415.         {EnterKey}    3: BEGIN
  416.                          END;
  417.         {LeftArrow}  28:;
  418.         {RightArrow} 29:;
  419.         {DownArrow}  31: BEGIN
  420.                          END;
  421.         {UpArrow}    30: BEGIN
  422.                          END;
  423.         {ascii}         32..255:
  424.                          BEGIN
  425.                          END;
  426.     END; {case}
  427. END;{DoKeyDown}
  428.  
  429.  
  430. PROCEDURE DoActivate(event:EventRecord);
  431. VAR
  432.     WhichWindow:WindowPtr;
  433.     Activating:boolean;
  434.     I,kind:integer;
  435.     tport : grafptr;
  436. BEGIN
  437.     getport(tport);
  438.     WhichWindow:=WindowPtr(event.message);
  439.     kind:=WindowPeek(WhichWindow)^.WindowKind;
  440.     Activating:= odd(event.modifiers);
  441.     IF whichwindow=mywindow THEN
  442.         BEGIN
  443.             IF Activating THEN
  444.                 BEGIN
  445.                     {draw things that need to be shown w/ activate}
  446.                     {this also needs to be done with a resume event}
  447.                 END
  448.             ELSE {not activating}
  449.                 BEGIN
  450.                     {erase things that need to be erased}
  451.                 END;
  452.         END; {if it's mywindow}
  453.  
  454.     IF (NOT activating) THEN
  455.         BEGIN
  456.             WhichWindow:=FrontWindow;
  457.             kind:=WindowPeek(WhichWindow)^.WindowKind;
  458.             {IF kind<0 THEN ConvertClipboard;} {DA has become active}
  459.         END;
  460. END;{DoActivate}
  461.  
  462.  
  463. PROCEDURE ScrollVolts(draweverything : boolean);
  464. VAR tport : grafptr;
  465.     x,fx : integer;
  466.     i,j : integer;
  467.     svstart,svend : integer;
  468.     r : rect;
  469.     rgh : rgnHandle;
  470. BEGIN
  471.     drawmod:=drawmod+1;
  472.     GetPort(tport);
  473.     setport(mywindow);
  474.     case sampledown of
  475.     1: if draweverything then
  476.             BEGIN
  477.                 with r do
  478.                     BEGIN
  479.                         top:=0;
  480.                         bottom:=257;
  481.                         left:=0;
  482.                         right:=svwidth+1;
  483.                     END;
  484.                 eraserect(r);
  485.                 
  486.                 if bmode in [seconds,dseconds] then
  487.                     BEGIN
  488.                         svend:=secEnd;
  489.                         svStart:=secEnd-svWidth;
  490.                     END
  491.                 else
  492.                     BEGIN
  493.                         svend:=minEnd;
  494.                         svStart:=minEnd-svWidth;
  495.                     END;
  496.                 if svStart<0 then svStart:=svStart+queueSize;
  497.                 x:=svstart;
  498.                 
  499.                 for i:=1 to svwidth do
  500.                     BEGIN
  501.                         case bmode of
  502.                             seconds: fx:=BAND(SecHistory[x].pvolts,$FF);
  503.                             minutes: fx:=BAND(MinHistory[x].pvolts,$FF);
  504.                             dseconds:fx:=(dSecHistory[x].pvolts)*4 +128;
  505.                             dminutes:fx:=(dMinHistory[x].pvolts)*4 + 128;
  506.                         end;{case}
  507.                         x:=(x+1)mod queuesize;
  508.                         if i=1 then moveto(i,256-fx);
  509.                         lineto(i,256-fx);
  510.                     END;
  511.             END
  512.         else
  513.             BEGIN {draw in new channel}
  514.                 with r do
  515.                     BEGIN
  516.                         top:=0;
  517.                         bottom:=257;
  518.                         left:=0;
  519.                         right:=svwidth-1;
  520.                     END;
  521.                 rgh:=NewRgn;
  522.                 RectRgn(rgh,r);
  523.                 
  524.                 ScrollRect(r,-1,0,rgh);
  525.                 DisposeRgn(rgh);
  526.                 with r do
  527.                     BEGIN
  528.                         top:=0;
  529.                         bottom:=257;
  530.                         left:=right-1;
  531.                         right:=svwidth+1;
  532.                     END;
  533.                 eraserect(r);
  534.                 if bmode in [seconds,dseconds] then
  535.                     BEGIN
  536.                         svend:=secEnd;
  537.                         svStart:=secEnd-svWidth;
  538.                     END
  539.                 else
  540.                     BEGIN
  541.                         svend:=minEnd;
  542.                         svStart:=minEnd-svWidth;
  543.                     END;
  544.                 if svStart<0 then svStart:=svStart+queueSize;
  545.                 x:=svstart;
  546.                 for i:=1 to svwidth do
  547.                     BEGIN
  548.                         case bmode of
  549.                             seconds: fx:=BAND(SecHistory[x].pvolts,$FF);
  550.                             minutes: fx:=BAND(MinHistory[x].pvolts,$FF);
  551.                             dseconds:fx:=(dSecHistory[x].pvolts)*8 +128;
  552.                             dminutes:fx:=(dMinHistory[x].pvolts)*8 + 128;
  553.                         end;{case}
  554.                         x:=(x+1)mod queuesize;
  555.                         {draw only last line segment}
  556.                         if i=svwidth-3 then moveto(i,256-fx);
  557.                         if i>=svwidth-2 then lineto(i,256-fx);
  558.                     END;
  559.             END;{draw only 1 event}
  560.     2,3,4 :if draweverything then {do it with sampledown}
  561.             BEGIN
  562.                 drawmod:=0;
  563.                 with r do
  564.                     BEGIN
  565.                         top:=0;
  566.                         bottom:=257;
  567.                         left:=0;
  568.                         right:=svwidth+1;
  569.                     END;
  570.                 eraserect(r);
  571.                 
  572.                 if bmode in [seconds,dseconds] then
  573.                     BEGIN
  574.                         svend:=secEnd;
  575.                         svStart:=secEnd-svWidth*sampledown;
  576.                     END
  577.                 else
  578.                     BEGIN
  579.                         svend:=minEnd;
  580.                         svStart:=minEnd-svWidth*sampledown;
  581.                     END;
  582.                 if svStart<0 then svStart:=svStart+queueSize;
  583.                 x:=svstart;
  584.                 
  585.                 for i:=1 to svwidth do
  586.                     BEGIN
  587.                         fx:=0;
  588.                         for j:=1 to sampledown do
  589.                             BEGIN
  590.                                 case bmode of
  591.                                     seconds: fx:=fx+BAND(SecHistory[x].pvolts,$FF);
  592.                                     minutes: fx:=fx+BAND(MinHistory[x].pvolts,$FF);
  593.                                     dseconds:fx:=fx+(dSecHistory[x].pvolts);
  594.                                     dminutes:fx:=fx+(dMinHistory[x].pvolts);
  595.                                 end;{case}
  596.                                 x:=(x+1)mod queuesize;
  597.                             END;{for}
  598.                         case sampledown of
  599.                         2:fx:=fx*2; {fx:=fx*4 div 2}
  600.                         3:fx:=(fx*4) div 3;
  601.                         4:; {fx:=fx*4 div 4}
  602.                         end;{case}
  603.                         if bmode in [dseconds,dminutes] then fx:=fx*2+128
  604.                         else fx:=fx div 4; {back to normal voltage scale}
  605.                         if i=1 then moveto(i,256-fx);
  606.                         lineto(i,256-fx);
  607.                     END;
  608.             END
  609.         else
  610.             BEGIN {draw in new channel}
  611.                 if drawmod=sampledown then drawmod:=0
  612.                 else 
  613.                     BEGIN
  614.                         setport(tport);
  615.                         exit(ScrollVolts);
  616.                     END;
  617.                 with r do
  618.                     BEGIN
  619.                         top:=0;
  620.                         bottom:=257;
  621.                         left:=0;
  622.                         right:=svwidth;
  623.                     END;
  624.                 
  625.                 rgh:=NewRgn;
  626.                 RectRgn(rgh,r);
  627.                 
  628.                 ScrollRect(r,-1,0,rgh);
  629.                 DisposeRgn(rgh);
  630.                 with r do
  631.                     BEGIN
  632.                         top:=0;
  633.                         bottom:=257;
  634.                         left:=right-1;
  635.                         right:=svwidth+1;
  636.                     END;
  637.                 eraserect(r);
  638.                 if bmode in [seconds,dseconds] then
  639.                     BEGIN
  640.                         svend:=secEnd;
  641.                         svStart:=secEnd-svWidth*sampledown;
  642.                     END
  643.                 else
  644.                     BEGIN
  645.                         svend:=minEnd;
  646.                         svStart:=minEnd-svWidth*sampledown;
  647.                     END;
  648.                 if svStart<0 then svStart:=svStart+queueSize;
  649.                 x:=svstart;
  650.                 for i:=1 to svwidth do
  651.                     BEGIN
  652.                         fx:=0;
  653.                         for j:=1 to sampledown do
  654.                             BEGIN
  655.                                 case bmode of
  656.                                     seconds: fx:=fx+BAND(SecHistory[x].pvolts,$FF);
  657.                                     minutes: fx:=fx+BAND(MinHistory[x].pvolts,$FF);
  658.                                     dseconds:fx:=fx+(dSecHistory[x].pvolts);
  659.                                     dminutes:fx:=fx+(dMinHistory[x].pvolts);
  660.                                 end;{case}
  661.                                 x:=(x+1)mod queuesize;
  662.                             END;{for}
  663.                         case sampledown of
  664.                         2:fx:=fx*2; {fx:=fx*4 div 2}
  665.                         3:fx:=(fx*4) div 3;
  666.                         4:; {fx:=fx*4 div 4}
  667.                         end;{case}
  668.                         if bmode in [dseconds,dminutes] then fx:=fx*2+128
  669.                         else fx:=fx div 4; {back to normal voltage scale}
  670.                         if i=svwidth-1 then moveto(i,256-fx);
  671.                         if i>=svwidth then lineto(i,256-fx);
  672.                     END;
  673.             END;{draw only 1 event}
  674.  
  675.     end; {case sampledown}
  676.     Setport(tport);
  677. END; {ScrollVolts}
  678.  
  679.  
  680. PROCEDURE DoUpdate(event:EventRecord);
  681. VAR
  682.     WhichWindow:WindowPtr;
  683.     kind:integer;
  684.     info : fontinfo;
  685.     i:integer;
  686.     tport : grafptr;
  687.     r,lrect,r1:rect;
  688.     pat:patHandle;
  689.     dummyhdl : pichandle;
  690.     astr, bstr:str255;
  691.     sw : integer;
  692.     hposn, vposn : integer;
  693.     ww : integer;
  694.     
  695.     
  696.         PROCEDURE DrawStringRight(s : str31; fw : integer);
  697.         VAR k : integer;
  698.             cp : boolean;
  699.         BEGIN
  700.             k:=StringWidth(s);
  701.             cp:=k>fw;
  702.             if cp then 
  703.                 BEGIN
  704.                     TextFace([condense]);
  705.                     k:=StringWidth(s);
  706.                 END;
  707.             Moveto(hposn+fw-k,vposn);
  708.             drawstring(s);
  709.             if cp then TextFace([]);
  710.         END;{DrawStringRight}
  711.         
  712.         PROCEDURE DrawStringLeft(s : str31; fw : integer);
  713.         VAR k : integer;
  714.             cp : boolean;
  715.         BEGIN
  716.             k:=StringWidth(s);
  717.             cp:=k>fw;
  718.             if cp then 
  719.                 BEGIN
  720.                     TextFace([condense]);
  721.                     k:=StringWidth(s);
  722.                 END;
  723.             Moveto(hposn,vposn);
  724.             drawstring(s);
  725.             if cp then TextFace([]);
  726.         END;{DrawStringLeft}
  727.         
  728.         PROCEDURE DrawStringCenter(s : str31; fw : integer);
  729.         VAR k : integer;
  730.             cp : boolean;
  731.         BEGIN
  732.             k:=StringWidth(s);
  733.             cp:=k>fw;
  734.             if cp then 
  735.                 BEGIN
  736.                     TextFace([condense]);
  737.                     k:=StringWidth(s);
  738.                 END;
  739.             Moveto(hposn+(fw div 2) - (k div 2),vposn);
  740.             drawstring(s);
  741.             if cp then TextFace([]);
  742.         END;{DrawStringCenter}
  743.         
  744. BEGIN
  745.     pat:=getPattern(132);    { the fill pattern }
  746.     WhichWindow := WindowPtr(event.message);
  747.     kind:=WindowPeek(WhichWindow)^.WindowKind;
  748.     
  749.     showwatch;
  750.     Updating:=true;
  751.     getport(tport);
  752.     setport(whichwindow);
  753.     BeginUpdate(WhichWindow);
  754.     
  755.     if whichwindow=mywindow then
  756.         BEGIN
  757.             {draw that which needs be drawn}
  758.             ScrollVolts(true);
  759.             {draw any controls that need to be shown - Minutes/Seconds
  760.                                                        Volts, ∂Volts}
  761.             with r do
  762.                 BEGIN
  763.                     top:=0;
  764.                     bottom:=260;
  765.                     left:=svwidth+2;
  766.                     right:=left+80;
  767.                 END;
  768.             eraserect(r);
  769.             
  770.             {Draw Labels}
  771.             TextFont(1);
  772.             TextSize(9);
  773.             TextFace([]);
  774.             if bmode in [seconds,minutes] then
  775.                 for i:=1 to 5 do {5.5,6,6.5,7,7.5 volts}
  776.                     BEGIN
  777.                         hposn:=svwidth+2;
  778.                         vposn:=(5-i)*50+18;
  779.                         moveto(hposn,vposn);
  780.                         lineto(hposn+10,vposn);
  781.                         hposn:=hposn+12;
  782.                         case i of
  783.                             1:astr:='5.5 volts';
  784.                             2:astr:='6.0 volts';
  785.                             3:astr:='6.5 volts';
  786.                             4:astr:='7.0 volts';
  787.                             5:astr:='7.5 volts';
  788.                         end; {case}
  789.                         DrawStringLeft(astr,40);
  790.                     END{for}
  791.             else
  792.                 for i:=-4 to 4 do {ticks on derivative scale}
  793.                     BEGIN
  794.                         hposn:=svwidth+2;
  795.                         vposn:=(5-i)*25+3;
  796.                         moveto(hposn,vposn);
  797.                         lineto(hposn+10,vposn);
  798.                         hposn:=hposn+12;
  799.                         
  800.                     END;{for}
  801.             TextFont(0);
  802.             TextSize(12);
  803.             textFace([]);
  804.             
  805.         END;{update mywindow}
  806.         
  807.     EndUpdate(WhichWindow);
  808.     setport(tport);
  809.     Updating:=false;
  810.     initcursor;
  811. END;{DoUpdate}
  812.  
  813.  
  814. PROCEDURE DoDrag(WhichWindow:WindowPtr; loc:point);
  815. VAR
  816.     WinRect,DragBounds:rect;
  817.     i, imagenum : integer;
  818. BEGIN
  819.     DragBounds:=ScreenBits.bounds;
  820.     DragWindow(WhichWindow,loc,DragBounds);
  821. END;{DoDrag}
  822.  
  823.  
  824. PROCEDURE DoMouseDown(event:EventRecord);
  825. VAR
  826.   WhichWindow:WindowPtr;
  827.   ThePart,ignore:integer;
  828.   byebye : boolean;
  829.   tport : grafptr;
  830.   loc : point;
  831.   invbox : boolean;
  832.   invrect,r,rtri : rect;
  833.   invbutton,oldbutton : integer;
  834.   devent: eventrecord;
  835.   i:integer;
  836.   mycell:point;
  837.   datalen : integer;
  838.   caninvbutton : boolean;
  839.   myhandle1,myhandle2 : pichandle;
  840. BEGIN
  841.     caninvbutton:=not ShouldIDoColor;
  842.     ThePart:=FindWindow(event.where,WhichWindow);
  843.     CASE ThePart OF
  844.         InDesk:;
  845.         InMenuBar:BEGIN
  846.                     UpdateMenus;
  847.                     DoMenuEvent(MenuSelect(event.where));
  848.                   END;
  849.         InSysWindow:SystemClick(Event,WhichWindow);
  850.         InContent:
  851.             BEGIN
  852.                 IF (WhichWindow=mywindow) THEN
  853.                     BEGIN
  854.                         {Figure out what to do...}
  855.                         getport(tport);
  856.                         setport(mywindow);
  857.                         loc:=event.where;
  858.                         globaltolocal(loc);
  859.  
  860.                         setport(tport);
  861.                                 
  862.                         Exit(DoMouseDown);
  863.                     END;
  864.                 IF WhichWindow<>FrontWindow THEN 
  865.                     BEGIN
  866.                         SelectWindow(WhichWindow);
  867.                     END;
  868.             END;{incontent}
  869.         InDrag:DoDrag(WhichWindow,event.where);
  870.         InGrow:{DoGrow(WhichWindow,event)};
  871.         InGoAway:
  872.             BEGIN
  873.                 byebye:=TrackGoAway(WhichWindow,event.where);
  874.             END;
  875.         InZoomIn,InZoomOut:{DoZoom(WhichWindow,event)};
  876.       END;
  877. END; {DoMouseDown}
  878.  
  879.  
  880. PROCEDURE DoDiskInsert(event:EventRecord);
  881. VAR p : point;
  882.     intjunk : integer;
  883.     
  884. BEGIN {DoDiskInsert}
  885.     IF (HiWord(event.message) <> NoErr) THEN
  886.         BEGIN
  887.             DiLoad;
  888.             SetPt(p, 100, 80);
  889.             intjunk := DiBadMount(p, event.message);
  890.             DiUnload;
  891.         END;
  892. END;{DoDiskInsert}
  893.  
  894.  
  895. FUNCTION HandleEvents : boolean;
  896. CONST
  897.     osevent = app4Evt;
  898.     suspendresumemessage = 1;
  899.     resumemask = 1;
  900.     mouemovedmessage = $FA;
  901. VAR
  902.     Event : EventRecord;
  903.     whichwindow : windowptr;
  904.     b : boolean;
  905.     thePart : integer;
  906.     myMenu : menuHandle;
  907.     
  908. BEGIN
  909.     b:=myGetNextEvent(everyEvent,Event); {should use WaitNextEvent if in background}
  910.     if b then {normal event, background update/activate, AEvent?}
  911.         with Event do
  912.             case what of
  913.                 KeyDown,AutoKey:DoKeyDown(event);
  914.                 MouseDown:DoMouseDown(event);
  915.                 ActivateEvt:DoActivate(event);
  916.                 DiskEvt:DoDiskInsert(event);
  917.                 UpdateEvt:DoUpdate(event);
  918.                 OSevent:case BSR(message,24) of
  919.                     mousemovedmessage:;
  920.                     suspendresumemessage: if band(message,resumemask)<>0 then
  921.                             BEGIN{resume event}
  922.                                 progstate:=foregroundP;
  923.                                 message:=ord4(frontwindow);
  924.                                 modifiers:=ord(true);{activate}
  925.                                 DoActivate(event); {multifinder aware}
  926.                             END
  927.                         else
  928.                             BEGIN
  929.                                 progstate:=backgroundP;
  930.                                 message:=ord4(frontwindow);
  931.                                 modifiers:=ord(false);{deactivate}
  932.                                 DoActivate(event); {multifinder aware}
  933.                                 {convert clipboard, if needed}
  934.                             END;
  935.                         END; {case message»24}
  936.                 END{case what, with}
  937.     else handleevents:=false;
  938. END;{handleEvents}
  939.  
  940.  
  941. PROCEDURE DoStartup;
  942. VAR i:integer;
  943. BEGIN
  944.     Finished:=false;
  945.     ProgState:=ForegroundP;
  946.     updating:=false;
  947.     hasWNE:=WNEIsImplemented;
  948.     
  949.     SecStart:=-1; {flag for first time}
  950.     SecEnd:=0; {queue indicies, SecEnd=location for next entry}
  951.     MinStart:=-1; {flag for first time}
  952.     MinEnd:=0; {queue indicies, minEnd=location for next entry}
  953.     
  954.     lastMinCount:=0; {flag for first time}
  955.     lastSecCount:=0; {flag for first time through}
  956.     
  957.     bmode:=seconds;
  958.     for i:=0 to queueSize-1 do
  959.         BEGIN
  960.             SecHistory[i].pvolts:=0;
  961.             dSecHistory[i].pvolts:=0;
  962.             SecHistory[i].pvolts:=0;
  963.             dSecHistory[i].pvolts:=0;
  964.         END;
  965.     sampledown:=1; {1,2,3, or 4}
  966. END; {DoStartup}
  967.  
  968.  
  969. PROCEDURE MakeWindow;
  970. VAR cell : point;
  971.     databounds, ibox : rect;
  972. BEGIN
  973.     if ShouldIDoColor then ; {set up the HasColor flag}
  974.     
  975.     if not HasColor then
  976.         mywindow:=GetNewWindow(1000,NIL,pointer(-1) )
  977.     else myWindow:=WindowPtr(GetNewCWindow(1000,NIL,pointer(-1)));
  978.     
  979.     UpdateMenus; {cannot update until the window is drawn}
  980.     
  981. END;{makewindow}
  982.  
  983.  
  984. FUNCTION SampleVolts : boolean;
  985. VAR now : longint;
  986.     IsIdle : boolean;
  987.     Volts : integer;
  988.     ModemOn : boolean;
  989.     isCharging : boolean;
  990.     
  991.     Function Sample : boolean;
  992.     VAR theErr : oserr;
  993.         status : byte;
  994.         power : byte;
  995.     BEGIN
  996.         isIdle:=GetCPUSpeed=1; {1MHz is idled}
  997.         theErr:=ModemStatus(status);
  998.         if theerr<>noerr then 
  999.             BEGIN
  1000.                 sample:=false;
  1001.                 exit(sample);
  1002.             END;
  1003.         
  1004.         ModemOn:=BAND(status,$01)=$01;
  1005.         
  1006.         power:=$AA;
  1007.         status:=$55;
  1008.         
  1009.         theErr:=BatteryStatus(status,power);
  1010.         
  1011.         if theErr<>noerr then
  1012.             BEGIN
  1013.                 sample:=false;
  1014.                 exit(sample);
  1015.             END;
  1016.             
  1017.         Volts:=GetVoltage; {  (512+power) div 100 = volts}
  1018.         isCharging:=(BAND(status,$01{connected})=$01);
  1019.         sample:=true;
  1020.     END;{sample}
  1021.     
  1022. BEGIN
  1023.     now:=TickCount;
  1024.     if lastSecCount=0 then
  1025.         BEGIN {initialize everything - 1 element in both queues, etc}
  1026.             if not Sample then
  1027.                 BEGIN
  1028.                     SampleVolts:=false;
  1029.                     exit(SampleVolts);
  1030.                 END;
  1031.             SecStart:=0;
  1032.             SecEnd:=0;
  1033.             
  1034.             with SecHistory[SecEnd] do
  1035.                 BEGIN
  1036.                     pIdle:=isIdle;
  1037.                     pvolts:=volts;
  1038.                     {pbacklight:= help barry}
  1039.                     pDiskOn:=true; {we'll assume on, later we will notice spikes and
  1040.                                     adjust this flag}
  1041.                     pSndOn:=false; {usually off}
  1042.                     pModemOn:=ModemOn;
  1043.                     pPortA:=false; {should really ask about this}
  1044.                     pPortB:=false; {should really ask about this}
  1045.                     pCharging:=isCharging;
  1046.                 END;{with}
  1047.                 
  1048.             dSecHistory[SecEnd]:=SecHistory[SecEnd];
  1049.             dSecHistory[SecEnd].pvolts:=0; {no change}
  1050.             
  1051.             SecEnd:=(SecEnd+1) mod QueueSize;
  1052.             
  1053.             SampleVolts:=true;
  1054.             lastSecCount:=now;
  1055.             if true then
  1056.                 BEGIN {add to per minute queue, may be forced to toss stale data}
  1057.                     MinStart:=0;
  1058.                     MinEnd:=0;
  1059.                     
  1060.                     with MinHistory[MinEnd] do
  1061.                         BEGIN
  1062.                             pIdle:=isIdle;
  1063.                             pvolts:=volts;
  1064.                             {pbacklight:= help barry}
  1065.                             pDiskOn:=true; {we'll assume on, later we will notice spikes and
  1066.                                             adjust this flag}
  1067.                             pSndOn:=false; {usually off}
  1068.                             pModemOn:=ModemOn;
  1069.                             pPortA:=false; {should really ask about this}
  1070.                             pPortB:=false; {should really ask about this}
  1071.                             pCharging:=isCharging;
  1072.                         END;{with}
  1073.                     
  1074.                     dMinHistory[MinEnd]:=MinHistory[MinEnd];
  1075.                     dMinHistory[MinEnd].pvolts:=0; {no change}
  1076.                     
  1077.                     MinEnd:=(MinEnd+1) mod QueueSize;
  1078.                 END;{add to minute history}
  1079.         END{first time through}
  1080.     else if now>=lastSecCount+SecTicks {60 ticks = 1 second} then
  1081.         BEGIN {add to second queue, may be forced to toss old data}
  1082.             if not Sample then
  1083.                 BEGIN
  1084.                     SampleVolts:=false;
  1085.                     exit(SampleVolts);
  1086.                 END;
  1087.             if SecStart=SecEnd then
  1088.                 SecStart:=(SecStart+1) mod QueueSize;
  1089.             
  1090.             with SecHistory[SecEnd] do
  1091.                 BEGIN
  1092.                     pIdle:=isIdle;
  1093.                     pvolts:=volts;
  1094.                     {pbacklight:= help barry}
  1095.                     pDiskOn:=true; {we'll assume on, later we will notice spikes and
  1096.                                     adjust this flag}
  1097.                     pSndOn:=false; {usually off}
  1098.                     pModemOn:=ModemOn;
  1099.                     pPortA:=false; {should really ask about this}
  1100.                     pPortB:=false; {should really ask about this}
  1101.                     pCharging:=isCharging;
  1102.                 END;{with}
  1103.                 
  1104.             dSecHistory[SecEnd]:=SecHistory[SecEnd];
  1105.             if SecEnd=0 then
  1106.                 dSecHistory[SecEnd].pvolts:=SecHistory[0].pvolts-SecHistory[QueueSize-1].pvolts
  1107.             else
  1108.                 dSecHistory[SecEnd].pvolts:=SecHistory[SecEnd].pvolts-SecHistory[SecEnd-1].pvolts;
  1109.     
  1110.             SecEnd:=(SecEnd+1) mod QueueSize;
  1111.             
  1112.             SampleVolts:=(bmode=seconds) or (bmode=dseconds);
  1113.             lastSecCount:=now;
  1114.             if lastSecCount>=lastMinCount+MinTicks then
  1115.                 BEGIN {add to per minute queue, may be forced to toss stale data}
  1116.                     if MinStart=MinEnd then
  1117.                         MinStart:=(MinStart+1) mod QueueSize;
  1118.                     lastmincount:=now;
  1119.                     with MinHistory[MinEnd] do
  1120.                         BEGIN
  1121.                             pIdle:=isIdle;
  1122.                             pvolts:=volts;
  1123.                             {pbacklight:= help barry}
  1124.                             pDiskOn:=true; {we'll assume on, later we will notice spikes and
  1125.                                             adjust this flag}
  1126.                             pSndOn:=false; {usually off}
  1127.                             pModemOn:=ModemOn;
  1128.                             pPortA:=false; {should really ask about this}
  1129.                             pPortB:=false; {should really ask about this}
  1130.                             pCharging:=isCharging;
  1131.                         END;{with}
  1132.                     
  1133.                     dMinHistory[MinEnd]:=MinHistory[MinEnd];
  1134.                     if SecEnd=0 then
  1135.                         dMinHistory[MinEnd].pvolts:=MinHistory[0].pvolts-MinHistory[QueueSize-1].pvolts
  1136.                     else
  1137.                         dMinHistory[MinEnd].pvolts:=MinHistory[MinEnd].pvolts-MinHistory[MinEnd-1].pvolts;
  1138.  
  1139.                     MinEnd:=(MinEnd+1) mod QueueSize;
  1140.                     
  1141.                     SampleVolts:=true;
  1142.                 END;{add to minute history}
  1143.         END{add to second queue}
  1144.     else SampleVolts:=false;
  1145. END; {SampleVolts}
  1146.  
  1147.  
  1148. BEGIN {Main Prog}
  1149.       SetApplLimit(ptr(LongInt(GetApplLimit)-16000));
  1150.       MaxApplZone;
  1151.     
  1152.       InitGraf(@ThePort);
  1153.       InitFonts;
  1154.     Flushevents(everyevent,0);
  1155.       InitWindows;
  1156.     InitMenus;
  1157.       TEInit;
  1158.       InitDialogs(@SysResume);
  1159.       InitCursor;
  1160.     
  1161.     SetUpMenus;
  1162.     DoStartup;
  1163.     MakeWindow;
  1164.     
  1165.     {Macsbug;}
  1166.         
  1167.     REPEAT {main event Loop}
  1168.         if not hasWNE then
  1169.             SystemTask; {actions defined for desk accessories}
  1170.         if HandleEvents then ;
  1171.         if SampleVolts then ScrollVolts(false);
  1172.     UNTIL finished;
  1173. END. {BattMonitor}